﻿namespace Centido.Core.Test
{
    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Testing indexes
    /// </summary>
    [TestClass]
    public class IndexTest
    {
        /// <summary>
        /// Domain name
        /// </summary>
        public const string DomainName = "FullAdminRights";

        /// <summary>
        /// Domain
        /// </summary>
        private Domain _domain;

        /// <summary>
        /// A table in the domain
        /// </summary>
        private Table _table;

        /// <summary>
        /// Name of that table
        /// </summary>
        private string _tableName;

        /// <summary>
        /// Initializing the test
        /// </summary>
        [TestInitialize]
        public void Initialize()
        {
            _domain = Domain.Build(DomainConfiguration.Load(DomainName));

            _domain.DeleteAllTables();

            _tableName = StringProperty.RandomIdentifier();

            var parameters = new TableParameters {DefaultIndexes = false};

            _table = _domain.AddTable(_tableName, parameters);

            _table.GrantAll();
        }

        /// <summary>
        /// Cleaning up after the test
        /// </summary>
        [TestCleanup]
        public void CleanUp()
        {
            _domain.DeleteAllTables();
        }

        /// <summary>
        /// Creating index on one column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnOneColumn()
        {
            //Creating one column
            var column = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);

            //Creating an index
            var index = _table.AddIndex(column);

            //Checking index properties
            Assert.IsNotNull(index);

            Assert.IsNotNull(index.Table);
            Assert.AreEqual(index.Table.Name, _table.Name);

            Assert.IsFalse(index.IsUnique);

            Assert.AreEqual(index.Columns.Count(), 1);
            Assert.AreEqual(index.Columns.Count(c => c.Name == column.Name), 1);
            Assert.IsTrue(index.Exists());

            //Checking table properties
            Assert.AreEqual(_table.Indexes.Count(), 1);
            Assert.AreEqual(_table.Indexes.Count(i => i.Id == index.Id), 1);
            Assert.IsNotNull(_table.GetIndex(index.Id));
            Assert.AreEqual(_table.GetIndex(index.Id).Id, index.Id);
        }

        /// <summary>
        /// Creating unique index on one column specifying id
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexOnOneColumnSpecifyingId()
        {
            //Creating one column
            var column = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);

            //Index id
            var indexId = Guid.NewGuid();

            //Creating an index
            var index = _table.AddIndex(indexId, true, column);

            Assert.IsNotNull(index);

            Assert.AreEqual(index.Id, indexId);
            Assert.IsTrue(index.IsUnique);
            Assert.IsTrue(index.Exists());
        }

        /// <summary>
        /// Creating index on one system column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnOneSystemColumn()
        {
            var index = _table.AddIndex(_table.SystemColumns.IsActive);

            Assert.IsNotNull(index);
            Assert.AreEqual(index.Columns.Count(c => c.Name == _table.SystemColumns.IsActive.Name), 1);
        }

        /// <summary>
        /// Creating index on two columns
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnTwoColumns()
        {
            //Creating two columns
            var firstColumn = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);
            var secondColumn = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);

            //Creating index on two columns
            var index = _table.AddIndex(firstColumn, secondColumn);

            Assert.IsNotNull(index);
            Assert.AreEqual(index.Columns.Count(), 2);
            Assert.IsTrue(index.Columns.Any(c => c.Name == firstColumn.Name));
            Assert.IsTrue(index.Columns.Any(c => c.Name == secondColumn.Name));
            Assert.IsTrue(index.Exists());
        }

        /// <summary>
        /// Creating index on two system columns
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnTwoSystemColumns()
        {
            //Creating index on two system columns
            var index = _table.AddIndex(_table.SystemColumns.Id, _table.SystemColumns.CreatedBy);

            Assert.IsNotNull(index);
            Assert.AreEqual(index.Columns.Count(), 2);
            Assert.IsTrue(index.Columns.Any(c => c.Name == _table.SystemColumns.Id.Name));
            Assert.IsTrue(index.Columns.Any(c => c.Name == _table.SystemColumns.CreatedBy.Name));
        }

        /// <summary>
        /// Creating index on system and user columns
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnSystemAndUserColumns()
        {
            //Creating user column
            var column = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);

            //Creating index on system and user columns
            var index = _table.AddIndex(column, _table.SystemColumns.IsActive);

            Assert.IsNotNull(index);
            Assert.AreEqual(index.Columns.Count(), 2);
            Assert.IsTrue(index.Columns.Any(c => c.Name == column.Name));
            Assert.IsTrue(index.Columns.Any(c => c.Name == _table.SystemColumns.IsActive.Name));
        }

        /// <summary>
        /// Passing nothing when creating an index
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentException), AllowDerivedTypes = true)]
        public void PassingNothingWhenCreatingIndex()
        {
            _table.AddIndex();
        }

        /// <summary>
        /// Passing null when creating an index
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentException), AllowDerivedTypes = true)]
        public void PassingNullWhenCreatingIndex()
        {
            _table.AddIndex(_table.SystemColumns.IsActive, null);
        }

        /// <summary>
        /// Passing duplicate columns when creating index
        /// </summary>
        [TestMethod]
        public void PassingDuplicateColumnsWhenCreatingIndex()
        {
            try
            {
                _table.AddIndex(_table.SystemColumns.Id, _table.SystemColumns.IsActive, _table.SystemColumns.Id);
            }
            catch (DbException)
            {
                Assert.AreEqual(_table.Indexes.Count, 0);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Creating duplicate indexes with different column positions
        /// </summary>
        [TestMethod]
        public void CreatingDuplicateIndexesWithDifferentColumnPositionsV1()
        {
            //Creating two indexes
            var firstIndex = _table.AddIndex(_table.SystemColumns.Id, _table.SystemColumns.IsActive);

            var secondIndex = _table.AddIndex(_table.SystemColumns.IsActive, _table.SystemColumns.Id);

            Assert.AreEqual(_table.Indexes.Count(), 2);
            Assert.AreEqual(_table.Indexes.Count(i => i.Id == firstIndex.Id), 1);
            Assert.AreEqual(_table.Indexes.Count(i => i.Id == secondIndex.Id), 1);
        }


        /// <summary>
        /// Creating duplicate indexes with different column positions (bug fix).
        /// </summary>
        [TestMethod]
        public void CreatingDuplicateIndexesWithDifferentColumnPositionsV2()
        {
            // Creating two indexes
            var firstIndex = _table.AddIndex(_table.SystemColumns.Id, _table.SystemColumns.IsActive);

            // The second index is unique
            var secondIndex = _table.AddIndex(true, _table.SystemColumns.IsActive, _table.SystemColumns.Id);

            Assert.IsNotNull(firstIndex);
            Assert.IsNotNull(secondIndex);

            Assert.IsFalse(firstIndex.IsUnique);
            Assert.IsTrue(secondIndex.IsUnique);

            Assert.AreEqual(_table.Indexes.Count(), 2);
            Assert.AreEqual(_table.Indexes.Count(i => i.Id == firstIndex.Id), 1);
            Assert.AreEqual(_table.Indexes.Count(i => i.Id == secondIndex.Id), 1);
        }


        /// <summary>
        ///   Creating unique indexes with the is_active column (bug fix).
        /// </summary>
        /// <remarks>The bug: is_active column was mentioned twice in
        /// the header of the uniqueness trigger.</remarks>
        [TestMethod]
        public void CreatingUniqueIndexesWithIsActiveColumn()
        {
            Assert.AreEqual(_table.Indexes.Count(), 0);

            _table.AddIndex(true, _table.SystemColumns.IsActive);
            _table.AddIndex(true, _table.SystemColumns.IsActive,
                _table.SystemColumns.Id);
            _table.AddIndex(true, _table.SystemColumns.Id,
                _table.SystemColumns.IsActive);

            Assert.AreEqual(_table.Indexes.Count(), 3);
        }


        /// <summary>
        /// Creating index with duplicate id
        /// </summary>
        [TestMethod]
        public void CreatingIndexWithDuplicateId()
        {
            var index = _table.AddIndex(_table.SystemColumns.Id);

            try
            {
                _table.AddIndex(index.Id, _table.SystemColumns.Owner);
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.AddingIndexWithDuplicateId);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Creating duplicate indexes with the same column positions
        /// </summary>
        [TestMethod]
        public void CreatingDuplicateIndexesWithTheSameColumnPositions()
        {
            //Creating two indexes
            _table.AddIndex(_table.SystemColumns.Id, _table.SystemColumns.IsActive);

            try
            {
                _table.AddIndex(_table.SystemColumns.Id, _table.SystemColumns.IsActive);
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.AddingIndexWithDuplicateColumnSet);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Creating id column index
        /// </summary>
        [TestMethod]
        public void CreatingIdIndex()
        {
            _table.AddIndex(_table.SystemColumns.Id);
        }

        /// <summary>
        /// Creating index on many columns
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnManyColumns()
        {
            //Creating the columns
            var columnList = new List<Column>();

            for (var i = 0; i < Index.IndexedColumnMaxCount; i++)
            {
                columnList.Add(_table.AddColumn("col" + i, ColumnType.Integer));
            }

            //Creating the index
            _table.AddIndex(columnList.ToArray());

            Assert.AreEqual(_table.Indexes.Count(), 1);
            Assert.AreEqual(_table.Indexes.ElementAt(0).Columns.Count(), Index.IndexedColumnMaxCount);
        }


        /// <summary>
        ///   Creating unique index on many columns.
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexOnManyColumns()
        {
            //Creating the columns
            var columnList = new List<Column>();

            for (var i = 0; i < Index.IndexedColumnMaxCount; i++)
            {
                columnList.Add(_table.AddColumn("col" + i, ColumnType.Integer));
            }

            //Creating the index
            var index = _table.AddIndex(true, columnList.ToArray());

            Assert.IsNotNull(index);
            Assert.AreEqual(_table.Indexes.Count(), 1);
            Assert.AreEqual(index.IsUnique, true);
            Assert.AreEqual(_table.Indexes.ElementAt(0).Columns.Count(), Index.IndexedColumnMaxCount);
        }

        /// <summary>
        /// Creating index on too many columns
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentException), AllowDerivedTypes = true)]
        public void CreatingIndexOnTooManyColumns()
        {
            //Creating the columns
            var columnList = new List<Column>();

            for (var i = 0; i < Index.IndexedColumnMaxCount + 1; i++)
            {
                columnList.Add(_table.AddColumn("col" + i, ColumnType.Integer));
            }

            //Creating the index
            _table.AddIndex(columnList.ToArray());
        }

        /// <summary>
        /// Creating unique index and inserting different values
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexAndInsertingDifferentValues()
        {
            //Creating a unique index
            var index = _table.AddIndex(true, _table.SystemColumns.Id);

            Assert.IsTrue(index.IsUnique);

            //Inserting different values
            _table.InsertRow();
            _table.InsertRow();

            Assert.AreEqual(_table.RowCount, 2);
        }

        /// <summary>
        /// Creating unique index and specifying duplicate values
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexAndInsertingDuplicateValues()
        {
            //Creating a unique index
            var index = _table.AddIndex(true, _table.SystemColumns.Id);

            Assert.IsTrue(index.IsUnique);

            //Inserting duplicate values
            var id = Guid.NewGuid();

            _table.InsertRow(id);

            try
            {
                _table.InsertRow(id);
            }
            catch (DbException)
            {
                Assert.AreEqual(_table.RowCount, 1);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Creating unique index after different values were inserted
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexAfterDifferentValuesWereInserted()
        {
            //Inserting different values
            _table.InsertRow();
            _table.InsertRow();

            Assert.AreEqual(_table.RowCount, 2);

            //Creating a unique index
            var index = _table.AddIndex(true, _table.SystemColumns.Id);

            Assert.IsTrue(index.IsUnique);
        }

        /// <summary>
        /// Creating unique index after duplicate values were inserted
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexAfterDuplicateValuesWereInserted()
        {
            //Inserting duplicate values
            var id = Guid.NewGuid();

            _table.InsertRow(id);
            _table.InsertRow(id);

            //Creating a unique index
            _table.AddIndex(true, _table.SystemColumns.Id);
        }

        /// <summary>
        /// Creating unique index and inserting different values
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexOnTwoColumnsAndInsertingDifferentValues()
        {
            //Creating two columns
            var firstColumn = _table.AddColumn("col1", ColumnType.Integer);
            var secondColumn = _table.AddColumn("col2", ColumnType.Integer);

            //Creating unique index
            _table.AddIndex(true, firstColumn, secondColumn);

            //Inserting different values
            _table.InsertRow(firstColumn.Value(1), secondColumn.Value(1));
            _table.InsertRow(firstColumn.Value(1), secondColumn.Value(2));
            _table.InsertRow(firstColumn.Value(2), secondColumn.Value(1));

            Assert.AreEqual(_table.RowCount, 3);
        }

        /// <summary>
        /// Creating unique index and inserting duplicate values
        /// </summary>
        [TestMethod]
        public void CreatingUniqueIndexOnTwoColumnsAndInsertingDuplicateValues()
        {
            //Creating two columns
            var firstColumn = _table.AddColumn("col1", ColumnType.Integer);
            var secondColumn = _table.AddColumn("col2", ColumnType.Integer);

            //Creating unique index
            _table.AddIndex(true, firstColumn, secondColumn);

            _table.InsertRow(firstColumn.Value(1), secondColumn.Value(1));

            try
            {
                _table.InsertRow(firstColumn.Value(1), secondColumn.Value(1));
            }
            catch (DbException)
            {
                Assert.AreEqual(_table.RowCount, 1);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Checking uniqueness on row update.
        /// </summary>
        [TestMethod]
        public void CheckingUniquenessOnUpdate()
        {
            // Creating a column
            var column = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index on the column
            _table.AddIndex(true, column);

            // Inserting a value
            var firstId = _table.InsertRow(column.Value(1));

            // Inserting another value
            var secondId = _table.InsertRow(column.Value(2));

            // Updating the first value
            _table.UpdateRow(firstId, column.Value(3));

            try
            {
                // Updating the second value
                column.Update(secondId, 3);
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.BreakingUniqueness);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Checking uniqueness with the recycle bin enabled.
        /// </summary>
        [TestMethod]
        public void CheckingUniquenessWithRecycleBinEnabled()
        {
            _domain.HasRecycleBin = true;

            // Creating a column
            var column = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index on the column
            _table.AddIndex(true, column);

            // Inserting a value
            var firstId = _table.InsertRow(column.Value(1));

            // Deleting that value to the recycle bin
            _table.DeleteRow(firstId);

            Assert.AreEqual(_table.RowCount, 0);
            Assert.AreEqual(_table.InternalRowCount, 1);

            // Inserting the same value
            var secondId = _table.InsertRow(column.Value(1));

            Assert.AreEqual(_table.RowCount, 1);
            Assert.AreEqual(_table.InternalRowCount, 2);

            // Deleting the second row
            _table.DeleteRow(secondId);
        }


        /// <summary>
        ///   Checking uniqueness on is_active column when the recycle bin is enabled.
        /// </summary>
        [TestMethod]
        public void CheckingUniquenessOnIsActiveWithRecycleBinEnabled()
        {
            _domain.HasRecycleBin = true;

            _table.AddIndex(true, _table.SystemColumns.IsActive);

            var id = _table.InsertRow();

            Assert.AreEqual(_table.RowCount, 1);

            _table.DeleteRow(id);

            id = _table.InsertRow();

            _table.DeleteRow(id); // Now there are two rows in the recycle bin

            _table.InsertRow();

            Assert.AreEqual(_table.RowCount, 1);

            // Trying to insert two active rows
            try
            {
                _table.InsertRow();
            }
            catch (DbException ex)
            {
                Assert.AreEqual(ex.GetErrorCode(), DbErrorCode.BreakingUniqueness);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Trying to restore a non-unique value.
        /// </summary>
        [TestMethod]
        public void TryingToRestoreNonUniqueValue()
        {
            _domain.HasRecycleBin = true;

            // Creating a column
            var column = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index on the column
            _table.AddIndex(true, column);

            // Inserting a value
            var firstId = _table.InsertRow(column.Value(1));

            // Deleting that value to the recycle bin
            _table.DeleteRow(firstId);

            Assert.AreEqual(_table.RowCount, 0);
            Assert.AreEqual(_table.InternalRowCount, 1);

            // Inserting the same value
            _table.InsertRow(column.Value(1));

            try
            {
                _table.RestoreRow(firstId);
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.BreakingUniqueness);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Checking uniqueness after column renaming.
        /// </summary>
        [TestMethod]
        public void CheckingUniquenessAfterColumnRenaming()
        {
            // Creating two columns
            var column1 = IntColumn.Add(_table, StringProperty.RandomIdentifier());
            var column2 = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index on the columns
            _table.AddIndex(true, column1, column2);

            // Inserting a value
            _table.InsertRow(column1.Value(1), column2.Value(2));

            // Renaming the second column
            column2.Name = StringProperty.RandomIdentifier();

            try
            {
                // Inserting the same values
                _table.InsertRow(column1.Value(1), column2.Value(2));
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.BreakingUniqueness);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Checking column uniqueness after table renaming.
        /// </summary>
        [TestMethod]
        public void CheckingUniquenessAfterTableRenaming()
        {
            // Creating a column
            var column = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index on the columns
            _table.AddIndex(true, column);

            // Inserting a value
            _table.InsertRow(column.Value(1));

            // Renaming the table
            _table.Name = StringProperty.RandomIdentifier();

            try
            {
                // Inserting the same value
                _table.InsertRow(column.Value(1));
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.BreakingUniqueness);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        ///   Removing a unique index.
        /// </summary>
        [TestMethod]
        public void RemovingUniqueIndex()
        {
            // Creating a column
            var column = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index on the column
            var index = _table.AddIndex(true, column);

            // Inserting a value
            _table.InsertRow(column.Value(1));

            // Removing the index
            index.Delete();

            // Inserting the same value
            _table.InsertRow(column.Value(1));

            Assert.AreEqual(_table.RowCount, 2);
        }


        /// <summary>
        ///   Deleting a column from a unique index.
        /// </summary>
        [TestMethod]
        public void DeletingColumnFromUniqueIndex()
        {
            // Creating two columns
            var column1 = IntColumn.Add(_table, StringProperty.RandomIdentifier());
            var column2 = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index on the columns
            _table.AddIndex(true, column1, column2);

            // Inserting a value
            _table.InsertRow(column1.Value(1), column2.Value(2));

            // Deleting the second column
            column2.Delete();

            // Inserting the same value
            _table.InsertRow(column1.Value(1));

            Assert.AreEqual(_table.RowCount, 2);
        }


        /// <summary>
        ///   Checking uniqueness when the recycle bin is disabled.
        /// </summary>
        [TestMethod]
        public void CheckingUniquenessWhenRecycleBinIsReenabled()
        {
            // Enabling the recycle bin
            _domain.HasRecycleBin = true;

            // Creating a column
            var column = IntColumn.Add(_table, StringProperty.RandomIdentifier());

            // Creating a unique index
            _table.AddIndex(true, column);

            // Inserting a value
            var id = _table.InsertRow(column.Value(1));

            // Deleting the first row
            _table.DeleteRow(id);

            // Inserting the same value
            _table.InsertRow(column.Value(1));

            // Deleting the second row
            _table.DeleteRow(id);

            // Disabling the recycle bin
            _domain.HasRecycleBin = false;

            Assert.AreEqual(_table.RowCount, 2);

            try
            {
                // Inserting the same value
                _table.InsertRow(column.Value(1));
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.BreakingUniqueness);
                return;
            }

            Assert.Fail();
        }


        /// <summary>
        /// Creating index on a text column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnTextColumn()
        {
            //Creating a text column
            var column = _table.AddColumn("t", ColumnType.Text);

            try
            {
                //Creating an index
                _table.AddIndex(column);
            }
            catch (DbException)
            {
                Assert.AreEqual(_table.Indexes.Count, 0);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Creating index on a binary column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnBinaryColumn()
        {
            //Creating a binary column
            var column = _table.AddColumn("b", ColumnType.Binary);

            try
            {
                //Creating an index
                _table.AddIndex(column);
            }
            catch (DbException)
            {
                Assert.AreEqual(_table.Indexes.Count, 0);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Creating index on a guid column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnGuidColumn()
        {
            //Creating a guid column
            var column = _table.AddColumn("g", ColumnType.Guid);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on a integer column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnIntegerColumn()
        {
            //Creating a integer column
            var column = _table.AddColumn("i", ColumnType.Integer);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on a big integer column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnBigIntegerColumn()
        {
            //Creating a integer column
            var column = _table.AddColumn("i", ColumnType.BigInteger);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on a small integer column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnSmallIntegerColumn()
        {
            //Creating a integer column
            var column = _table.AddColumn("i", ColumnType.SmallInteger);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on an enum column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnEnumColumn()
        {
            //Creating a enum column
            var column = _table.AddColumn("e", ColumnType.Enumeration);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on a decimal column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnDecimalColumn()
        {
            //Creating a decimal column
            var column = _table.AddColumn("d", ColumnType.Decimal);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on a datetime column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnDateTimeColumn()
        {
            //Creating a datetime column
            var column = _table.AddColumn("d", ColumnType.DateTime);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on a ref column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnRefColumn()
        {
            //Creating a ref column
            var column = _table.AddColumn("ref", ColumnType.Reference);

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Creating index on a string column
        /// </summary>
        [TestMethod]
        public void CreatingIndexOnStringColumn()
        {
            //Creating a string column
            var column = _table.AddColumn("s", ColumnType.String) as StringColumn;

            if (column == null) return;

            //Setting max length!!!
            column.MaxLength = 64;

            //Creating an index
            var index = _table.AddIndex(column);

            Assert.IsNotNull(index);
        }

        /// <summary>
        /// Renaming column that was indexed
        /// </summary>
        [TestMethod]
        public void RenamingColumnThatWasIndexed()
        {
            //Creating a columns
            var column = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);

            //Creating an index
            var index = _table.AddIndex(column);

            //Renaming the column
            var newColumnName = StringProperty.RandomIdentifier();

            column.Name = newColumnName;

            Assert.AreEqual(column.Name, newColumnName.ToLower());
            Assert.AreEqual(index.Columns.Count(), 1);
            Assert.AreEqual(index.Columns.Count(c => c.Name == newColumnName.ToLower()), 1);
        }

        /// <summary>
        /// Deleting column that was indexed
        /// </summary>
        [TestMethod]
        public void DeletingColumnThatWasIndexed()
        {
            //Creating a column
            Column column = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);

            //Creating an index
            _table.AddIndex(column);

            Assert.AreEqual(_table.Indexes.Count(), 1);

            //Deleting the column
            column.Delete();

            Assert.AreEqual(_table.Indexes.Count(), 0);
        }

        /// <summary>
        /// Deleting one of the columns that were indexed
        /// </summary>
        [TestMethod]
        public void DeletingOneOfTheColumnsThatWereIndexed()
        {
            //Creating a column
            Column column = _table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Integer);

            //Creating an index
            _table.AddIndex(column, _table.SystemColumns.IsActive);

            Assert.AreEqual(_table.Indexes.Count(), 1);

            //Deleting the column
            column.Delete();

            Assert.AreEqual(_table.Indexes.Count(), 0);
        }

        /// <summary>
        /// Deleting an index
        /// </summary>
        [TestMethod]
        public void DeletingIndex()
        {
            //Creating an index
            var index = _table.AddIndex(_table.SystemColumns.RowVersion);

            Assert.AreEqual(_table.Indexes.Count(), 1);

            //Deleting the index
            _table.DeleteIndex(index.Id);

            Assert.AreEqual(_table.Indexes.Count(), 0);
            Assert.IsFalse(index.Exists());
        }

        /// <summary>
        /// Deleting index that was deleted
        /// </summary>
        [TestMethod]
        public void DeletingIndexThatWasDeleted()
        {
            var index = _table.AddIndex(_table.SystemColumns.Id);

            _table.DeleteIndex(index);

            try
            {
                index.Delete();
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.DeletingNonexistentIndex);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Chacking table default indexes
        /// </summary>
        [TestMethod]
        public void CheckingTableDefaultIndexes()
        {
            var table = _domain.AddTable(StringProperty.RandomIdentifier());

            Assert.AreEqual(table.Indexes.Count(), 2);
            Assert.AreEqual(table.Indexes.Count(i => i.IsUnique && i.Columns.Count() == 1), 1);
            Assert.AreEqual(table.Indexes.Count(i => !i.IsUnique && i.Columns.Count() == 1), 1);
        }
    }
}